﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Xml;
using System.Xml.XPath;
using ATTools.Models;
using Orchard.Caching;
using Orchard.ContentManagement;
using Orchard.Environment.Extensions;
using Orchard.Localization.Services;
using Orchard.Services;
using Orchard.Settings;

namespace ATTools.Services
{
    [OrchardFeature("ATTools")]
    public class TranslationService : ITranslationService
    {
        private readonly ISiteService _siteService;
        private readonly ICultureManager _cultureManager;
        private readonly ICacheManager _cacheManager;
        private readonly IClock _clock;

        public TranslationService(ISiteService siteService, ICultureManager cultureManager, ICacheManager cacheManager, IClock clock)
        {
            _siteService = siteService;
            _cultureManager = cultureManager;
            _cacheManager = cacheManager;
            _clock = clock;
        }

        #region ITranslationService Members

        public IEnumerable<string> GetAvailableLanguages()
        {

            string appId = _siteService.GetSiteSettings().As<ATToolsSettingsPart>().Record.BingAppID;
            IEnumerable<string> voices = new List<string>();

            voices = _cacheManager.Get("bingTranslationLanguages", ctx =>
            {
                IEnumerable<string> languages = new List<string>();

                string uri = "http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=" + appId;
                HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);

                try
                {
                    WebResponse resp = httpWebRequest.GetResponse();
                    Stream strm = resp.GetResponseStream();

                    System.Runtime.Serialization.DataContractSerializer dcs = new System.Runtime.Serialization.DataContractSerializer(typeof(List<string>));
                    languages = (List<string>)dcs.ReadObject(strm);

                }
                catch (Exception)
                {
                    ctx.Monitor(_clock.When(TimeSpan.FromDays(0)));
                    return languages;
                }

                //Cache the languages for 24 hours
                ctx.Monitor(_clock.When(TimeSpan.FromDays(1)));

                return languages;

            });

            return voices;

        }

        public IEnumerable<string> DetectLanguages(string[] texts)
        {
            string appId = _siteService.GetSiteSettings().As<ATToolsSettingsPart>().Record.BingAppID;
            string uri = "http://api.microsofttranslator.com/v2/Http.svc/DetectArray?appId=" + appId;

            // create the request
            StringWriter swriter = new StringWriter();
            XmlTextWriter xwriter = new XmlTextWriter(swriter);

            xwriter.WriteStartElement("ArrayOfstring");
            xwriter.WriteAttributeString("xmlns", "http://schemas.microsoft.com/2003/10/Serialization/Arrays");

            foreach (string text in texts)
            {
                xwriter.WriteStartElement("string");
                xwriter.WriteString(text);
                xwriter.WriteEndElement();
            }

            xwriter.WriteEndElement();

            xwriter.Close();
            swriter.Close();
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
            req.ContentType = "text/xml";
            req.Method = "POST";
            System.IO.Stream stream = req.GetRequestStream();

            byte[] arrBytes = System.Text.Encoding.UTF8.GetBytes(swriter.ToString());
            stream.Write(arrBytes, 0, arrBytes.Length);
            stream.Close();

            IEnumerable<string> langs = new List<string>();

            try
            {
                // get the response
                WebResponse resp = req.GetResponse();
                Stream respStream = resp.GetResponseStream();
                System.Runtime.Serialization.DataContractSerializer dcs = new System.Runtime.Serialization.DataContractSerializer(typeof(List<string>));
                langs = (List<string>)dcs.ReadObject(respStream);
                respStream.Close();

            }
            catch (Exception)
            {
                return langs;
            }
            return langs;

        }

        public IEnumerable<string> GetLanguageNames(string[] languageCodes, bool localized = true)
        {


            string appId = _siteService.GetSiteSettings().As<ATToolsSettingsPart>().Record.BingAppID;
            string siteCulture = _cultureManager.GetSiteCulture();
            string uri = "http://api.microsofttranslator.com/v2/Http.svc/GetLanguageNames?appId=" + appId + "&locale=" + siteCulture;

            if (!localized)
                uri = "http://api.microsofttranslator.com/v2/Http.svc/GetLanguageNames?appId=" + appId;

            IEnumerable<string> languageNames = new List<string>();
            string hash = (siteCulture + localized.ToString() + languageCodes.ToString()).GetHashCode().ToString();
            languageNames = _cacheManager.Get("bingLanguageNames" + hash, ctx =>
            {
                try
                {
                    // get the input list
                    string[] input = languageCodes;
                    System.Runtime.Serialization.DataContractSerializer dcs = new System.Runtime.Serialization.DataContractSerializer(input.GetType());

                    // create the request
                    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
                    req.ContentType = "text/xml";
                    req.Method = "POST";
                    System.IO.Stream stream = req.GetRequestStream();
                    dcs.WriteObject(stream, input);
                    stream.Close();


                    // get the response
                    WebResponse resp = req.GetResponse();
                    Stream respStream = resp.GetResponseStream();
                    string[] result = (string[])dcs.ReadObject(respStream);
                    respStream.Close();

                    //Cache the languagenames for 24 hours
                    ctx.Monitor(_clock.When(TimeSpan.FromDays(1)));

                    return result.ToList<string>();
                }

                catch (Exception)
                {
                    ctx.Monitor(_clock.When(TimeSpan.FromDays(0)));
                    return new List<string>(); //Return the empty list
                }

            });

            return languageNames;

        }

        public IEnumerable<string> Translate(string[] texts, string languageFrom, string languageTo, bool html = false)
        {
            string appId = _siteService.GetSiteSettings().As<ATToolsSettingsPart>().Record.BingAppID;
            string uri = "http://api.microsofttranslator.com/v2/Http.svc/TranslateArray?appId=" + appId;

            StringWriter swriter = new StringWriter();
            XmlTextWriter xwriter = new XmlTextWriter(swriter);

            xwriter.WriteStartElement("TranslateArrayRequest");

            xwriter.WriteStartElement("AppId");
            xwriter.WriteString(appId);
            xwriter.WriteEndElement();

            xwriter.WriteStartElement("From");
            xwriter.WriteString(languageFrom);
            xwriter.WriteEndElement();

            xwriter.WriteStartElement("Options");

            xwriter.WriteStartElement("Category");
            xwriter.WriteAttributeString("xmlns", "http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2");
            xwriter.WriteEndElement();

            xwriter.WriteStartElement("ContentType");
            xwriter.WriteAttributeString("xmlns", "http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2");
            if (html)
            {
                xwriter.WriteString("text/html");
            }

            else
            {
                xwriter.WriteString("text/plain");
            }
            
            xwriter.WriteEndElement();

            xwriter.WriteStartElement("ReservedFlags");
            xwriter.WriteAttributeString("xmlns", "http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2");
            xwriter.WriteEndElement();

            xwriter.WriteStartElement("State");
            xwriter.WriteAttributeString("xmlns", "http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2");
            xwriter.WriteEndElement();

            xwriter.WriteStartElement("Uri");
            xwriter.WriteAttributeString("xmlns", "http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2");
            xwriter.WriteEndElement();

            xwriter.WriteStartElement("User");
            xwriter.WriteAttributeString("xmlns", "http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2");
            xwriter.WriteEndElement();

            xwriter.WriteEndElement();

            xwriter.WriteStartElement("Texts");
            foreach (string text in texts)
            {
                xwriter.WriteStartElement("string");
                xwriter.WriteAttributeString("xmlns", "http://schemas.microsoft.com/2003/10/Serialization/Arrays");
                xwriter.WriteString(text);
                xwriter.WriteEndElement();
            }
            xwriter.WriteEndElement();

            xwriter.WriteStartElement("To");
            xwriter.WriteString(languageTo);
            xwriter.WriteEndElement();

            xwriter.WriteEndElement();

            xwriter.Close();
            swriter.Close();


            // create the request
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
            req.ContentType = "text/xml";
            req.Method = "POST";
            System.IO.Stream stream = req.GetRequestStream();
            byte[] arrBytes = System.Text.Encoding.UTF8.GetBytes(swriter.ToString());
            stream.Write(arrBytes, 0, arrBytes.Length);
            stream.Close();

            // get the response
            WebResponse resp = req.GetResponse();
            Stream respStream = resp.GetResponseStream();

            XPathDocument doc = new XPathDocument(respStream);
            XPathNavigator navigator = doc.CreateNavigator();

            XmlNamespaceManager ns = new XmlNamespaceManager(navigator.NameTable);
            ns.AddNamespace("t", "http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2");

            //Get the translations
            XPathNodeIterator nodes = navigator.Select("//t:TranslatedText", ns);

            List<string> translations = new List<string>();

            while (nodes.MoveNext())
            {
                XPathNavigator node = nodes.Current;
                translations.Add(node.Value);

            }

            respStream.Close();

            return translations;

        }

        #endregion
    }
}